package com.huang.transport;

import com.huang.transport.netty.client.NettyClient;
import com.huang.transport.socket.client.SocketRpcClient;
import com.huangwei.entity.RpcRequest;
import com.huangwei.entity.RpcResponse;
import com.huangwei.util.RpcMessageChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

/**
 * RPC客户端动态代理
 */
public class RpcClientProxy implements InvocationHandler {

    private static final Logger logger = LoggerFactory.getLogger(RpcClientProxy.class);
    private final RpcClient rpcClient;
    public RpcClientProxy(RpcClient rpcClient){
        this.rpcClient = rpcClient;
    }

    //生成对应类名的代理类实例
    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> clazz){
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[]{clazz},this);
    }

    //代理类具体执行方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        logger.info("调用方法：{}#{}", method.getDeclaringClass().getName(), method.getName());
        //生成request对象
        RpcRequest rpcRequest = new RpcRequest(UUID.randomUUID().toString(), method.getDeclaringClass().getName(),
                method.getName(), args, method.getParameterTypes(), false);
        RpcResponse rpcResponse = null;
        if(rpcClient instanceof NettyClient){
            try {
                CompletableFuture<RpcResponse> completableFuture = (CompletableFuture<RpcResponse>)rpcClient.sendRequest(rpcRequest);
                rpcResponse = completableFuture.get();
            } catch (Exception e) {
                logger.error("方法调用请求发送失败", e);
                return null;
            }
        }
        //利用网络io将将request对象传出，得到response对象
        if (rpcClient instanceof SocketRpcClient) {
            rpcResponse = (RpcResponse)rpcClient.sendRequest(rpcRequest);
        }
        //校验id号
        RpcMessageChecker.check(rpcRequest,rpcResponse);
        return rpcResponse.getData();
    }

}
